package edu.swe632.otm.resources;

import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.ws.rs.CookieParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;

@Path("/alternates")
public class AlternateRouteResource {

	private static int computerIdCounter = 0;

	private final DecimalFormat computerIdFormat = new DecimalFormat("0000");

	/**
	 * A really dumb login method that logs any username in.
	 * 
	 * @param username
	 *            the username
	 * @param password
	 *            the password
	 * @return a reponse
	 */
	@POST
	@Path("/{username}")
	public Response login(@PathParam("username")
	String username, @CookieParam("computerId")
	String computerId) {
		if(computerId != null) {
			for(Route route : ResourceStore.SAVED.getAllComputerRoutes(computerId)) {
				route.setCreatorUserName(username);
			}
		}
		Response.ResponseBuilder responseBuilder = Response.noContent();
		NewCookie cookie = new NewCookie("username", username);
		responseBuilder.cookie(cookie);
		return responseBuilder.build();
	}

	/**
	 * Publishes a stored route
	 */
	@PUT
	@Path("/publish/{name}")
	public Response publishAlternateRouteData(@CookieParam("username")
	String username, @CookieParam("computerId")
	String computerId, @PathParam("name")
	String name, String content) {
		String[] addresses = content.split(";");
		Endpoints endpoint = new Endpoints(addresses[0],
				addresses[addresses.length - 1]);
		Route route = new Route();
		route.setAddresses(Arrays.asList(addresses));
		route.setEndpoint(endpoint);
		route.setName(name);

		Response.ResponseBuilder responseBuilder = Response.noContent();

		if (username != null) {
			ResourceStore.SAVED.removeRouteForUser(endpoint.getStartAddress(),
					endpoint.getDestinationAddress(), username);
			route.setCreatorUserName(username);
			if (computerId != null) {
				ResourceStore.SAVED.removeRouteForComputer(endpoint
						.getStartAddress(), endpoint.getDestinationAddress(),
						username);
				route.setCreatorComputerId(computerId);
			}
			ResourceStore.PUBLISHED.addRoute(route);
		} else if (computerId != null) {
			responseBuilder = Response.status(401);
		} else {
			responseBuilder = Response.status(401);
			String newComputerId = "C" + computerIdFormat.format(computerIdCounter++);
			NewCookie cookie = new NewCookie("computerId", newComputerId);
			responseBuilder.cookie(cookie);
			route.setCreatorComputerId(newComputerId);
		}
		return responseBuilder.build();

	}

	/**
	 * Stores data for an alternate route
	 */
	@PUT
	@Path("/store")
	public Response storeAlternateRouteData(@CookieParam("username")
	String username, @CookieParam("computerId")
	String computerId, String content) throws IOException {
		String[] addresses = content.split(";");
		Endpoints endpoint = new Endpoints(addresses[0],
				addresses[addresses.length - 1]);
		Route route = new Route();
		route.setAddresses(Arrays.asList(addresses));
		route.setEndpoint(endpoint);

		Response.ResponseBuilder responseBuilder = Response.noContent();

		if (username != null) {
			ResourceStore.SAVED.removeRouteForUser(endpoint.getStartAddress(),
					endpoint.getDestinationAddress(), username);
			route.setCreatorUserName(username);
			if (computerId != null) {
				route.setCreatorComputerId(computerId);
			}
		} else if (computerId != null) {
			ResourceStore.SAVED.removeRouteForComputer(endpoint
					.getStartAddress(), endpoint.getDestinationAddress(),
					computerId);
			route.setCreatorComputerId(computerId);
		} else {
			String newComputerId = "C" + computerIdFormat.format(computerIdCounter++);
			NewCookie cookie = new NewCookie("computerId", newComputerId);
			responseBuilder.cookie(cookie);
			route.setCreatorComputerId(newComputerId);
		}
		ResourceStore.SAVED.addRoute(route);
		return responseBuilder.build();
	}

	/**
	 * Gets an HTML representation of alternate routes, if they exist
	 */
	@GET
	@Path("/{saddr}/{daddr}")
	@Produces("text/html")
	public String getAlternateRouteList(@CookieParam("username")
	String username, @CookieParam("computerId")
	String computerId, @PathParam("saddr")
	String saddr, @PathParam("daddr")
	String daddr) {
		System.out.println("Looking for " + saddr + " - " + daddr + " in "
				+ ResourceStore.PUBLISHED);
		List<Route> publishedRoutes = ResourceStore.PUBLISHED.getRoutesFor(saddr, daddr);
		String html = "<p>Click and drag the route to create an alternate.</p>";
		if(publishedRoutes != null)
		{
			html = html + "<div id=\"published\">" + getHtml(publishedRoutes, true) + "</div>";
		}
		
		List<Route> sandboxRoutes = new ArrayList<Route>();
		if(username != null)
		{
			Route sandbox = ResourceStore.SAVED.getRouteForUser(saddr, daddr, username);
			if(sandbox != null)
			{
				sandbox.setName("(Unpublished)");
				sandboxRoutes.add(sandbox);
			}
		}
		else if(computerId != null)
		{
			Route sandbox = ResourceStore.SAVED.getRouteForComputer(saddr, daddr, computerId);
			if(sandbox != null)
			{
				sandbox.setName("(Unpublished)");
				sandboxRoutes.add(sandbox);
			}
		}
		if(!sandboxRoutes.isEmpty())
		{
			html = html + "<div id=\"sandbox\">" + getHtml(sandboxRoutes, false) + "</div>";
		}
		
		if(!sandboxRoutes.isEmpty() || publishedRoutes != null && !publishedRoutes.isEmpty())
		{
			html = html + "<a href=\"javascript:hideOriginalPolyline()\">Hide Original</a>";
		}
		return html;
	}

	private String getHtml(List<Route> routes, boolean published) {
		StringBuilder html = new StringBuilder("<ul>");
		for (int i = 0; i < routes.size(); i++) {
			Route route = routes.get(i);
			String saddr = route.getEndpoint().getStartAddress();
			String daddr = route.getEndpoint().getDestinationAddress();

			if(published)
			{
				html.append("<li><a href=\"javascript:displayAlternate(" + i + 
					"," + saddr + "," + daddr + ")\">" + 
					route.getName() + "</a></li>");
			}
			else
			{
				html.append("<li><a href=\"javascript:displaySandbox('" + 
						route.getCreatorComputerId() + 
						"'," + saddr + "," + daddr + ")\">" + 
						route.getName() + "</a></li>");
			}
		}
		html.append("</ul>");
		return html.toString();
	}

	@Path("/published/{saddr}/{daddr}/{number}")
	@GET
	public String getAlternateRouteQueryString(@PathParam("saddr")
	String saddr, @PathParam("daddr")
	String daddr, @PathParam("number")
	int number) {
		
		System.out.println("ALTERNATE " + saddr + "/" + daddr + "/" + number
				+ " REQUESTED");
		
		Route route = ResourceStore.PUBLISHED.getRoute(new Endpoints(saddr,
				daddr), number);
		List<String> addresses = route.getAddresses();
		if (addresses.size() < 2) {
			throw new IllegalArgumentException("Route is misconfigured");
		}
		StringBuilder builder = new StringBuilder("from: " + addresses.get(0));
		for (int i = 1; i < addresses.size(); i++) {
			builder.append(" to: " + addresses.get(i));
		}
		return builder.toString();
	}
	
	@Path("/sandbox/{saddr}/{daddr}/{computerId}")
	@GET
	public String getAlternateRouteQueryString(@PathParam("saddr")
	String saddr, @PathParam("daddr")
	String daddr, @PathParam("computerId")
	String computerId) {
		System.out.println("ALTERNATE " + saddr + "/" + daddr + "/" + computerId
				+ " REQUESTED");
		Route route = ResourceStore.SAVED.getRouteForComputer(saddr, daddr,
				computerId);
		List<String> addresses = route.getAddresses();
		if (addresses.size() < 2) {
			throw new IllegalArgumentException("Route is misconfigured");
		}
		StringBuilder builder = new StringBuilder("from: " + addresses.get(0));
		for (int i = 1; i < addresses.size(); i++) {
			builder.append(" to: " + addresses.get(i));
		}
		return builder.toString();
	}
}